namespace SimpleWebServices.Models
{
    using System;
    using System.Xml.Serialization;
    using SimpleWebServices.Xml;

    [XmlRoot("url", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
    public sealed class SiteMapUrl : ValueObject<SiteMapUrl>, IXmlSerializerNamespaces
    {
        private XmlSerializerNamespaces _declarations;
        private string _changefreq;

        public SiteMapUrl()
        {
            this.RegisterProperty(x => x.ChangeFrequency);
            this.RegisterProperty(x => x.LastModified);
            this.RegisterProperty(x => x.Location);
            this.RegisterProperty(x => x.Priority);

            this._declarations = new XmlSerializerNamespaces();
            this._declarations.Add(string.Empty, "http://www.sitemaps.org/schemas/sitemap/0.9");
        }

        [XmlElement("changefreq", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
        public string ChangeFrequency
        {
            get
            {
                return this._changefreq;
            }

            set
            {
                if (null == value)
                {
                    this._changefreq = null;
                }
                else if (0 == value.Length)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                else
                {
                    switch (value)
                    {
                        case "always":
                        case "hourly":
                        case "daily":
                        case "weekly":
                        case "monthly":
                        case "yearly":
                        case "never":
                            this._changefreq = value;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException("value");
                    }
                }
            }
        }

        [XmlIgnore]
        public DateTime? LastModified
        {
            get;
            set;
        }

        [XmlElement("lastmod", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
        public string LastModifiedValue
        {
            get
            {
                string value = null;

                if (this.LastModified.HasValue)
                {
                    if (this.LastModified.Value.Date == this.LastModified.Value)
                    {
                        value = this.LastModified.ToXmlString().Substring(0, 10);
                    }
                    else
                    {
                        value = this.LastModified.ToXmlString();
                    }
                }

                return value;
            }

            set
            {
                if (null == value)
                {
                    this.LastModified = null;
                }
                else if (0 == value.Length)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                else if (10 == value.Length)
                {
                    this.LastModified = (value + "T00:00:00").ConvertTo<DateTime>();
                }
                else
                {
                    this.LastModified = value.ConvertTo<DateTime>();
                }
            }
        }

        [XmlIgnore]
        public AbsoluteUri Location
        {
            get;
            set;
        }

        [XmlElement("loc", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
        public string LocationValue
        {
            get
            {
                return this.Location;
            }

            set
            {
                this.Location = value;
            }
        }

        [XmlIgnore]
        public float? Priority
        {
            get;
            set;
        }

        [XmlElement("priority", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
        public string PriorityValue
        {
            get
            {
                string value = null;

                if (this.Priority.HasValue)
                {
                    value = this.Priority.ToXmlString();
                }

                return value;
            }

            set
            {
                if (null == value)
                {
                    this.Priority = null;
                }
                else if (0 == value.Length)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                else
                {
                    switch (value)
                    {
                        case "0.0":
                            this.Priority = 0;
                            break;

                        case "0.1":
                            this.Priority = 0.1f;
                            break;

                        case "0.2":
                            this.Priority = 0.2f;
                            break;

                        case "0.3":
                            this.Priority = 0.3f;
                            break;

                        case "0.4":
                            this.Priority = 0.4f;
                            break;

                        case "0.5":
                            this.Priority = 0.5f;
                            break;

                        case "0.6":
                            this.Priority = 0.6f;
                            break;

                        case "0.7":
                            this.Priority = 0.7f;
                            break;

                        case "0.8":
                            this.Priority = 0.8f;
                            break;

                        case "0.9":
                            this.Priority = 0.9f;
                            break;

                        case "1.0":
                            this.Priority = 1;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException("value");
                    }
                }
            }
        }

        [XmlNamespaceDeclarations]
        public XmlSerializerNamespaces XmlNamespaceDeclarations
        {
            get
            {
                return this._declarations;
            }

            set
            {
                this._declarations = value;
            }
        }
    }
}